# -*- coding: utf-8 -*-
import os, sys
import traceback
import json
import time
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..'))
from CommonLib.PageCrawler.HttpsAccess import HttpsAccess
from CommonLib.mylog import mylog
import supeanut_config


'''
作者：supeanut
创建时间：2016-12-09 15:17
功能描述：
	数据接口免费，需要不定期续约！
	通联数据python接口，自动重连尝试
	获取包括：交易日历、每日停复牌、股票上市数据（上市退市股本）等数据
相关配置：
	supeanut_config.DATAYES API
历史改动：
	2016-12-11: gzip忽略处理
'''
class DatayesAPI:
	def __init__(self):
		self.host = supeanut_config.DATAYES_API_HOST
		self.port = supeanut_config.DATAYES_API_HTTPS_PORT
		self.headers = supeanut_config.DATAYES_HTTPS_HEADERS
		self.timeout = supeanut_config.DATAYES_TIMEOUT
		self.method = supeanut_config.DATAYES_HTTPS_METHOD
		self.try_max = supeanut_config.DATAYES_TRYMAX
		self.stockinfo = supeanut_config.DATAYES_API_STOCKINFO
		self.stocksuspend = supeanut_config.DATAYES_API_STOCKSUSPEND
		self.tradecalendar = supeanut_config.DATAYES_API_TRADECALENDAR
		self.codec = supeanut_config.DATAYES_API_ENCODE

	# DATAYES基础访问函数
	# INPUT: 相对访问路径（utf-8）
	# OUTPUT: json_dict(unicode) or msg
	def access_data(self, path):
		log = mylog('DataAPI.DatayesAPI.access_data', None)
		# 基础访问函数
		https_client = HttpsAccess()
		flag, msg = https_client.init_client(host = self.host,
											 port = self.port,
											 headers = self.headers,
											 timeout = self.timeout,
											 method = self.method,
											 codec = self.codec,
											 gzip_ignore = False)
		if flag is False:
			return False, msg
		# 尝试n次连接
		try_count = 0
		try_flag = False
		try_msg = ""
		while try_count < self.try_max:
			try_count += 1
			https_client.set_gzip_ignore(False)
			flag, try_msg = https_client.get_response(path)
			if flag is True:
				try_flag = True
				break
			# 因未gzip解压而导致的解码错误，或不需要gzip解压导致的错误
			if flag is False and ((try_msg.find("decode failed")>=0) or (try_msg.find("read gzip stream failed")>=0)):
				# 尝试忽略gzip解码
				https_client.set_gzip_ignore(True)
				flag, try_msg = https_client.get_response(path)
				if flag is True:
					try_flag = True
					break
			# 访问失败，休10秒
			time.sleep(10)
		if try_flag is False:
			return False, try_msg
		# jsoni load
		response_str = try_msg
		try:
			response = json.loads(response_str)
		except:
			log.exception("json loads failed: %s"%response_str)
			return False, "json loads failed"
		# 判断返回的数据合法性
		if not isinstance(response, dict):
			log.error("response dataform is not dict")
			return False, "response dataform is not dict"
		if not ('retCode' in response and 'retMsg' in response and 'data' in response):
			log.error('api result has not retCode and retMsg and data. result:%s'%response_str)
			return False, 'api result has not retCode and retMsg and data'
		# 判断接口是否正常返回
		retCode = response.get('retCode', None)
		retMsg = response.get('retMsg', None)
		data = response.get('data', None)
		if retCode is None or retMsg is None or data is None:
			log.error('retCode and retMsg and data has None')
			return False, 'retCode and retMsg and data has None'
		if retCode == 1 and retMsg == 'Success':
			return True, data
		else:
			return False, retMsg
		

	# 股票基本信息
	# 无数据内容的统一为： “no data”
	# status字段意义：L - 上市，S - 暂停，DE - 终止上市，UN - 未上市
	# total_shares字段：单位为股，乘以股价既可得到市值
	# 返回utf8格式{"300033":{"status":"L", ...}, ...}
	def stock_info(self):
		flag, data = self.access_data(self.stockinfo)
		if flag is False:
			return False, data
		result = {}
		for item in data:
			stock_code = item['ticker'].encode('utf-8')
			# 与配置文件的csv写入顺序相对应，保持统一
			result[stock_code] = {'board': item.get('ListSector', 'no data').encode('utf-8'),
									  'short_name': item.get('secShortName', 'no data').encode('utf-8'),
									  'full_name': item.get('secShortName', 'no data').encode('utf-8'),
									  'status': item.get('listStatusCD', 'no data').encode('utf-8'),
									  'total_shares': str(item.get('totalShares', 'no data')),
									  'circulate_shares': str(item.get('nonrestfloatA', 'no data')),
									  'intomarket_date': item.get('listDate', 'no data').encode('utf-8'),
									  'outmarket_date': item.get('delistDate', 'no data').encode('utf-8')}
		return True, result

	
	# 当日的停复牌信息
	# 返回utf8格式{'hold':['300033', ...], 'recover':['300033', ...]}
	def stock_suspension(self):
		url_path_R = self.stocksuspend + 'R'
		url_path_H = self.stocksuspend + 'H'
		flag, data_R = self.access_data(url_path_R)
		if flag is False:
			return False, data_R
		flag, data_H = self.access_data(url_path_H)
		if flag is False:
			return False, data_H
		result = {'hold': [], 'recover': []}
		for item in data_R:
			result['recover'].append(item['ticker'].encode('utf-8'))
		for item in data_H:
			result['hold'].append(item['ticker'].encode('utf-8'))
		return True, result


	# 获取1992年到下一年的交易日历
	# 上交所XSHG，深交所XSHE
	# {'2001-09-14': {'isOpen': 1, 'prevTradeDate': '2001-09-13', 'exchangeCD': 'XSHG'}, ...
	def trade_calendar(self):
		flag, data = self.access_data(self.tradecalendar)
		if flag is False:
			return False, data
		result = {}
		for item in data:
			date = item['calendarDate'].encode('utf-8')
			result[date] = {'isOpen': str(item.get('isOpen', 'no data')),
									  'prevTradeDate': item.get('prevTradeDate', 'no data').encode('utf-8'),
									  'exchangeCD': item.get('exchangeCD', 'no data').encode('utf-8')}
		return True, result


if __name__ == '__main__':
	obj = DatayesAPI()
	print(obj.stock_info())
	#print(obj.stock_suspension())
	#print(obj.trade_calendar())
